package cn.hy.goods;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;

import java.util.Collections;

/**
 * 限量控制
 */
@Component
public class RedisDecrementStock {

    private StringRedisTemplate stringRedisTemplate;

    private static final StringBuilder lua = new StringBuilder();

    private final RedisScript<Number> redisScript;

    /**
     * 该代码的主要流程如下：
     * 1. 先判断商品id是否存在，如果不存在则直接返回。
     * 2. 获取该商品id的库存，判断库存如果是-1，则直接返回，表示不限制库存。
     * 3. 如果库存大于0，则扣减库存。
     * 4. 如果库存等于0，是直接返回，表示库存不足。
     */
    static {
        lua.append("if (redis.call('exists', KEYS[1]) == 1) then");
        lua.append("    local stock = tonumber(redis.call('get', KEYS[1]));");
        lua.append("    if (stock == -1) then");
        lua.append("        return 1;");
        lua.append("    end;");
        lua.append("    if (stock > 0) then");
        lua.append("        redis.call('incrby', KEYS[1], -1);");
        lua.append("        return stock;");
        lua.append("    end;");
        lua.append("    return 0;");
        lua.append("end;");
        lua.append("return -1;");
    }

    private static final int SUCCESS_RESULT = 1;
    private static final int FAIL_RESULT = 0;

    public RedisDecrementStock(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
        redisScript = new DefaultRedisScript<>(lua.toString(), Number.class);
    }

    /**
     * 是否允许访问
     *
     * @param goodsId goodsId
     * @return 获取成功true，否则false
     * @throws IllegalArgumentException
     */
    public boolean execute(String goodsId) throws IllegalArgumentException {
        Number result = stringRedisTemplate.execute(redisScript, Collections.singletonList(goodsId));
        if (result != null && result.intValue() > 0) {
            return true;
        }
        if (result != null && result.intValue() == -1) {
            return true;
        }
        return false;
    }

}
